package fileSelection;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

import fileProcessors.FileFormatException;
import fileProcessors.FileProcessor;
import fileProcessors.PanelFileProcessor;

public class FileSelector implements ActionListener {
	private MainFrame frame;
	private JFileChooser dirChooser;
	private File currentDirectory;
	private File currentOutputFile;
	private File[] matchingFiles;
	private String[] excludes;
	private String[] includes;
	private FileProcessor activeFileProcessor;
	private ArrayList<FileProcessor> fileProcessors;

	public FileSelector() {
		frame = new MainFrame(this);
		frame.setVisible(true);
		this.currentDirectory = new File(System.getProperty("user.dir"));
		// change current directory to programm start path
		frame.changeDirectory(currentDirectory.getAbsolutePath());

		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent ev) {
				// saveSettings();
				System.exit(0);
			}
		});

		this.fileProcessors = new ArrayList<FileProcessor>();
		// loadSettings();
		frame.changeDirectory(currentDirectory.getAbsolutePath());
	}

	public void addMode(FileProcessor fp) {
		fileProcessors.add(fp);
		frame.addMode(fp.getClass().getSimpleName(), fp.getID());
		// display the first loaded file processor
		if (fileProcessors.size() == 1) {
			frame.setMode(fp.getTxtResult(), fp.getTxtProcessBtn(), fp.getTxtExcludeFilename(), fp.getTxtIncludeFilename(), fp.getClass()
					.getSimpleName());
		}
		displayVersionInfo();
	}

	public void saveSettings() {
		URL urlSettingsFile = this.getClass().getResource("Settings.res");
		File settings = new File(urlSettingsFile.getPath());
		try {
			BufferedWriter bw = new BufferedWriter(new FileWriter(settings));
			bw.write(currentDirectory.getAbsolutePath());
			bw.newLine();
			bw.write(frame.getFileNameInclude());
			bw.newLine();
			bw.write(frame.getFileNameExclude());
			bw.newLine();
			bw.write(frame.getFileNameResult());
			bw.newLine();
			bw.write(String.valueOf(frame.getIncludeSubfolders()));
			bw.newLine();
			bw.write(String.valueOf(frame.getOverwrite()));
			bw.close();
		} catch (IOException e) {
			return;
		}
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		String ac = e.getActionCommand();
		if (ac.equals("btn_change_dir")) {
			chooseNewDirectory();
		} else if (ac.equals("Cancel_Processor_Options")) {
			frame.displayNewFiles(matchingFiles);
		} else if (ac.equals("OK_Processor_Options")) {
			calculatePanelFileProcessor();
		} else if (ac.equals("btn_search_files")) {
			readIncludesExcludesFromFrame();
			searchFiles(currentDirectory, frame.getIncludeSubfolders());
		} else if (ac.equals("btn_process")) {
			calculate();
		} else if (ac.equals("AC_COMM_VERSIONINFO")) {
			displayVersionInfo();
		} else {
			// jmenuButtons query
			for (int i = 0; i < fileProcessors.size(); i++) {
				if (("AC_COMM_MODE" + fileProcessors.get(i).getID()).equals(e.getActionCommand())) {
					activeFileProcessor = fileProcessors.get(i);
					frame.setMode(activeFileProcessor.getTxtResult(), activeFileProcessor.getTxtProcessBtn(), activeFileProcessor.getTxtExcludeFilename(),
							activeFileProcessor.getTxtIncludeFilename(), activeFileProcessor.getClass().getSimpleName());
					break;
				}
			}
		}
	}

	private void calculatePanelFileProcessor() {
		try {
			activeFileProcessor.processFiles();
			frame.setStatus("All files processed.");
		} catch (RuntimeException e) {
			frame.setStatus(e.getClass().getSimpleName()+": "+e.getMessage());
		} finally {
			frame.showFile(currentOutputFile);
		}
	}

	private void displayVersionInfo() {
		String info = "Version info:\n\n";
		for (int i = 0; i < fileProcessors.size(); i++) {
			FileProcessor fp = fileProcessors.get(i);
			info += fp.getClass().getSimpleName() + " (" + fp.getDate() + ")\n";
			info += fp.getInformation() + "\n\n";
		}
		frame.showInfo(info);
	}

	private void calculate() {
		try {
			boolean[] checked = frame.checkCheckBoxes();
			if (checked == null) {
				frame.setStatus("No data selected.");
				return;
			}
			int remainingFiles = 0;
			for (int i = 0; i < checked.length; i++) {
				if (!checked[i]) {
					matchingFiles[i] = null;
				}
				if (matchingFiles[i] != null) {
					remainingFiles++;
				}
			}

			File[] remaining = new File[remainingFiles];
			int j = 0;
			for (int i = 0; i < matchingFiles.length; i++) {
				if (matchingFiles[i] != null) {
					remaining[j] = matchingFiles[i];
					j++;
				}
			}
			matchingFiles = remaining;

			currentOutputFile = new File(currentDirectory, frame.getFileNameResult());
			if (this.currentOutputFile.exists() && !frame.getOverwrite()) {
				int n = JOptionPane.showConfirmDialog(frame, "Ausgabedatei �berschreiben?", "Warnung",
						JOptionPane.YES_NO_OPTION);
				switch (n) {
				case JOptionPane.NO_OPTION:
					return;
				default:
					break;
				}
			}
			
			if (activeFileProcessor == null) {
				try {
					activeFileProcessor = fileProcessors.get(0);
				} catch (Exception e) {
					frame.setStatus("Warning: No File Processors available");
				}
			}
			// hand over all information to to the current file processor 
			activeFileProcessor.setOutputFile(this.currentOutputFile);
			activeFileProcessor.setFiles(this.matchingFiles);
			activeFileProcessor.setCurrentDirectory(this.currentDirectory);
			if (activeFileProcessor instanceof PanelFileProcessor) {
				frame.displayProcessorOptions(((PanelFileProcessor) (activeFileProcessor)).getPanel());
				((PanelFileProcessor) (activeFileProcessor)).getOkButton().removeActionListener(this);
				((PanelFileProcessor) (activeFileProcessor)).getOkButton().addActionListener(this);
				((PanelFileProcessor) (activeFileProcessor)).getCancelButton().removeActionListener(this);
				((PanelFileProcessor) (activeFileProcessor)).getCancelButton().addActionListener(this);
				// cancel and wait till one of the buttons is clicked. The calculation itself is done in
				// calculatePanelFileProcessor()
				return;
			}
			try {
				activeFileProcessor.processFiles();
				frame.setStatus("All files processed.");
			} catch (FileFormatException e) {
				frame.setStatus("ERROR: At least one of the input files is invalid.");
			} finally {
				frame.showFile(currentOutputFile);
			}
		} catch (Exception e) {
			e.printStackTrace();
			frame.setStatus("Severe program error...see stack trace.");
		}
	}

	private void readIncludesExcludesFromFrame() {
		excludes = frame.getFileNameExclude().split(" ");
		includes = frame.getFileNameInclude().split(" ");
	}

	public ArrayList<File> searchFiles(File directory, boolean includeSubfolders) {
		File[] files = directory.listFiles();
		ArrayList<File> matches = new ArrayList<File>();
		if (files != null) {
			for (int i = 0; i < files.length; i++) {
				if (!files[i].isDirectory()) {
					//look for all includes, only add file once
					boolean containsAll = true;
					for (int j = 0; j < includes.length; j++) {
						if (!files[i].getName().contains(includes[j])) {
							// checks whether the filename contains the active include string
							// ignoring upper/lower case differences
							containsAll = false;
							break;
						}
					}
					if (containsAll) {
						matches.add(files[i]);
					}
				} else if (includeSubfolders) {
					matches.addAll(searchFiles(files[i], includeSubfolders));
					// add the files from the subfolder to the overarching list
				}
			}

		}
		for (int i = 0; i < excludes.length; i++) {
			if (!excludes[0].equals("")) {
				for (int j = 0; j < matches.size(); j++) {
					if (matches.get(j).getName().contains(excludes[i])) {
						matches.remove(j);
						// reduce counter by one as the next element is shifted by one now
						j--;
					}
				}
			}

		}

		matchingFiles = new File[matches.size()];
		for (int i = 0; i < matches.size(); i++) {
			matchingFiles[i] = matches.get(i);
		}

		frame.displayNewFiles(matchingFiles);
		return matches;
	}
	
	

	private void chooseNewDirectory() {
		dirChooser = new JFileChooser();
		dirChooser.setCurrentDirectory(currentDirectory);
		dirChooser.setDialogTitle("New Directory");
		dirChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		// disable the "All files" option.
		dirChooser.setAcceptAllFileFilterUsed(false);
		//
		if (dirChooser.showOpenDialog(dirChooser) == JFileChooser.APPROVE_OPTION) {
			currentDirectory = dirChooser.getSelectedFile();
			frame.changeDirectory(currentDirectory.getAbsolutePath());
		}
	}
}